const { Service } = require('egg');
const UploadUtil = require('../utils/uploadUtil');
const fs = require('fs');
const path = require('path');

/**
 * 上传服务
 */
class UploadService extends Service {
  constructor(ctx) {
    super(ctx);
    this.uploadUtil = new UploadUtil(this.app);
  }

  /**
   * 上传图片
   * @param {object} file 文件对象
   * @param {string} category 图片分类
   * @param {string[]} tags 图片标签数组
   * @return {Promise<object>} 上传结果
   */
  async uploadImage(file, category = '', tags = []) {
    const { ctx } = this;

    // 检查文件类型是否为图片
    const imageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/webp'];
    if (!imageTypes.includes(file.mime)) {
      ctx.throw(500, '只允许上传图片文件');
    }


    // 检查文件大小 - 使用文件系统获取实际大小
    const maxSize = 5 * 1024 * 1024; // 5MB
    const fs = require('fs');
    const stats = fs.statSync(file.filepath);
    const fileSize = file.size || stats.size;

    if (!fileSize || fileSize > maxSize) {
      ctx.throw(500, '图片大小不能超过5MB');
    }

    // 更新文件大小
    file.size = fileSize;

    // 生成文件路径
    const pathInfo = this.uploadUtil.generateFilePath(file.filename);

    // 保存文件
    await this.uploadUtil.saveFile(fs.createReadStream(file.filepath), pathInfo.fullFilePath);

    // 获取文件类型
    const ext = path.extname(file.filename).toLowerCase().substring(1);
    const now = new Date();

    // 从token中获取用户信息
    const userId = ctx.state.user?.id || null;
    const username = ctx.state.user?.username || null;

    // 获取配置文件中的图片前缀
    const imageUrlPrefix = this.config.upload.imageUrlPrefix || '';

    // 构建图片URL：配置前缀 + URL路径
    // 使用uploadUtil中的generateImageUrlPath方法确保与文件路径生成逻辑一致
    const urlPath = this.uploadUtil.generateImageUrlPath(pathInfo.randomName);

    // 将图片信息保存到数据库
    // fileName保存原始文件名，filePath保存实际文件路径
    const imageInfo = {
      fileName: file.filename, // 保存原始文件名
      filePath: pathInfo.filePath,
      fileSize: file.size || 0, // 确保fileSize不为null
      fileType: ext,
      url: `${imageUrlPrefix}/${urlPath}`,
      uploadTime: now,
      category: category || null,
      tags: tags || [],
      uploadedById: userId,
      uploadedBy: username,
    };

    const savedImage = await this.app.model.Image.create(imageInfo);

    // 返回结果
    // 在返回结果中同时包含原始文件名和实际保存的文件名
    return {
      id: savedImage.id,
      url: imageInfo.url,
      filePath: imageInfo.filePath,
      fileName: savedImage.fileName, // 原始文件名
      savedFileName: pathInfo.randomName, // 实际保存的文件名
      size: imageInfo.fileSize,
      type: imageInfo.fileType,
      uploadTime: imageInfo.uploadTime,
      category: savedImage.category,
      tags: savedImage.tags,
      uploadedById: savedImage.uploadedById,
      uploadedBy: savedImage.uploadedBy,
    };
  }

  /**
   * 删除图片
   * @param {string} filePath 文件路径
   * @return {Promise<boolean>} 删除结果
   */
  async deleteImage(filePath) {
    const { ctx } = this;
    if (!filePath) {
      ctx.throw(500, '请提供要删除的图片路径');
    }

    // 从数据库中删除图片记录
    const image = await this.app.model.Image.findOne({
      where: { filePath },
    });

    if (image) {
      await image.destroy();
    }

    // 删除物理文件
    const fullFilePath = path.join(this.app.baseDir, filePath);

    // 同时尝试删除实际保存的文件
    return this.uploadUtil.deleteFile(fullFilePath);
  }

  /**
   * 获取图片信息
   * @param {string} id 图片ID
   * @return {Promise<object>} 图片信息
   */
  async getImageInfo(id) {
    const { ctx } = this;
    if (!id) {
      ctx.throw(500, '请提供图片ID');
    }

    // 先从数据库中查找图片信息，获取原始文件名
    const image = await this.app.model.Image.findByPk(id);

    if (!image) {
      ctx.throw(404, '图片不存在');
    }

    const filePath = image.filePath;
    const fullFilePath = path.join(this.app.baseDir, filePath);
    if (!fs.existsSync(fullFilePath)) {
      ctx.throw(500, '图片文件不存在');
    }

    const stats = fs.statSync(fullFilePath);
    const ext = path.extname(fullFilePath).toLowerCase();

    return {
      id: image.id,
      filePath,
      fileName: image.fileName, // 原始文件名
      name: path.basename(fullFilePath), // 实际保存的文件名
      size: stats.size,
      type: ext.substring(1), // 去掉点号
      uploadTime: image.uploadTime,
      createTime: stats.birthtime,
      modifyTime: stats.mtime,
      category: image.category,
      tags: image.tags,
      uploadedBy: image.uploadedBy,
      uploadedById: image.uploadedById,
    };
  }

  /**
   * 批量删除图片
   * @param {string[]} ids 图片ID数组
   * @return {Promise<object>} 删除结果
   */
  async batchDeleteImages(ids) {
    const { ctx } = this;
    if (!Array.isArray(ids) || ids.length === 0) {
      ctx.throw(500, '请提供要删除的图片ID数组');
    }

    // 先从数据库中查找要删除的图片记录
    const images = await this.app.model.Image.findAll({
      where: {
        id: ids,
      },
    });

    const filePaths = images.map(image => image.filePath);

    // 从数据库中删除记录
    await this.app.model.Image.destroy({
      where: {
        id: ids,
      },
    });

    // 再删除物理文件
    const result = {
      success: [],
      failed: [],
    };

    for (const filePath of filePaths) {
      try {
        const fullFilePath = path.join(this.app.baseDir, filePath);
        const deleted = this.uploadUtil.deleteFile(fullFilePath);
        if (deleted) {
          result.success.push(filePath);
        } else {
          result.failed.push({ filePath, reason: '文件不存在' });
        }
      } catch (error) {
        result.failed.push({ filePath, reason: error.message });
      }
    }

    return result;
  }


  /**
   * 获取图片列表
   * @param {object} params 查询参数
   * @param {number} params.pageNum 页码
   * @param {number} params.pageSize 每页数量
   * @param {string} params.category 分类
   * @param {string[]} params.tags 标签
   * @param {string} params.startTime 开始时间
   * @param {string} params.endTime 结束时间
   * @param {string} params.fileName 文件名
   * @return {Promise<object>} 图片列表和分页信息
   */
  async getImageList(params) {
    const { pageNum = 1, pageSize = 10, category, tags, startTime, endTime, fileName } = params;
    const offset = (pageNum - 1) * pageSize;
    const where = {};

    // 分类筛选
    if (category) {
      where.category = category;
    }

    // 标签筛选
    if (tags && tags.length > 0) {
      // 由于tags字段是JSON字符串格式，需要使用LIKE操作符进行模糊匹配
      const tagConditions = [];
      tags.forEach(tag => {
        const tagStr = tag.toString();
        tagConditions.push({ [this.app.Sequelize.Op.like]: `"${tagStr}"` }); // 精确匹配标签值
        tagConditions.push({ [this.app.Sequelize.Op.like]: `%"${tagStr}"%` }); // 包含标签值
      });

      where.tags = {
        [this.app.Sequelize.Op.or]: tagConditions
      };
    }

    // 时间范围筛选
    if (startTime || endTime) {
      where.uploadTime = {};
      if (startTime) {
        where.uploadTime[this.app.Sequelize.Op.gte] = new Date(startTime);
      }
      if (endTime) {
        where.uploadTime[this.app.Sequelize.Op.lte] = new Date(endTime);
      }
    }

    // 文件名筛选
    if (fileName) {
      where.fileName = {
        [this.app.Sequelize.Op.like]: `%${fileName}%`
      };
    }

    // 查询数据
    const { count, rows } = await this.app.model.Image.findAndCountAll({
      where,
      offset,
      limit: pageSize,
      order: [['uploadTime', 'DESC']],
    });


    return {
      total: count,
      list: rows,
      pageNum,
      pageSize,
    };
  }

  /**
   * 修改图片信息
   * @param {string} id 图片ID
   * @param {object} data 要修改的数据
   * @param {string} data.category 分类
   * @param {string[]} data.tags 标签
   * @return {Promise<boolean>} 是否修改成功
   */
  async updateImageInfo(id, data) {
    const { ctx } = this;
    if (!id) {
      ctx.throw(500, '请提供图片ID');
    }

    const image = await this.app.model.Image.findByPk(id);
    if (!image) {
      ctx.throw(500, '图片不存在');
    }

    const { fileName, category, tags } = data;
    const updateData = {};

    if (fileName !== undefined) {
      updateData.fileName = fileName || null;
    }

    if (category !== undefined) {
      updateData.category = category || null;
    }

    if (tags !== undefined) {
      updateData.tags = tags || [];
    }

    updateData.updateTime = new Date();

    await image.update(updateData);
    return true;
  }

  /**
   * 批量修改图片信息
   * @param {string[]} ids 图片ID数组
   * @param {object} data 要修改的数据
   * @param {string} data.category 分类
   * @param {string[]} data.tags 标签
   * @return {Promise<object>} 修改结果
   */
  async batchUpdateImageInfo(ids, data) {
    const { ctx } = this;
    if (!Array.isArray(ids) || ids.length === 0) {
      ctx.throw(500, '请提供要修改的图片ID数组');
    }

    const { category, tags } = data;
    const updateData = {};

    if (category !== undefined) {
      updateData.category = category || null;
    }

    if (tags !== undefined) {
      updateData.tags = tags || [];
    }

    if (Object.keys(updateData).length === 0) {
      ctx.throw(500, '请提供要修改的数据');
    }

    updateData.updateTime = new Date();

    // 更新数据库记录
    const result = await this.app.model.Image.update(updateData, {
      where: {
        id: ids,
      },
    });

    return {
      success: result[0] > 0,
      count: result[0],
    };
  }
}
module.exports = UploadService;
